基于Keycloak的权限控制

您所在的位置:网站首页 宝宝来了 电视剧 基于Keycloak的权限控制

基于Keycloak的权限控制

2024-05-31 01:36| 来源: 网络整理| 查看: 265

Keycloak授权介绍

Keycloak提供了一套基于策略的权限控制,主要的控制对象是被保护的资源,通常是一个或者多个URIs。

Keycloak的权限控制通过所谓的PEP(Policy Enforcement Point)即:策略执行点来操作。

Keycloak授权系统的实体对象

如上图所以,把所有授权实体分成了三个大的部分。

最上面的部分,我称之为资源定义,负责设置哪些资源(resource)的那些范围(scope)要被权限控制。资源通常是一个或者一组URI,比如/protected/*,而范围(scope)是一个很灵活的概念,既可以是对资源的CRUD,也可以是具有某一种特质的一组对象。通常,我们可以用scope来标识对资源的CRUD,比如:urn:demo:protected:view,urn:demo:protected:delete等等。

下面的部分,我称之为执行策略,负责设置执行权限的方式。比如,可以根据用户是否属于某个角色来检查权限,或者可以根据时间来检查权限等等,这里我列出了一些常用的执行策略,其实每个策略对应的一个权限模型:

基于角色的权限控制基于用户的权限控制基于组的权限控制(组可以有层级关系)基于时间的权限控制基于正则表达式的权限控制

中间的部分,我称之为权限关联,负责把执行策略与资源进行绑定。

Keycloak关于授权的设置

在Keycloak中,授权相关的配制,绝大部分都在具体的客户端设置里面。并且必须开启授权开关。

集成Keycloak授权功能

在Keycloak上对资源的权限进行配置以后,就可以通过编程的方式,来利用Keycloak来保护我们的微服务(也称资源服务器)了。

keycloak权限设置

既可以通过keycloak的admin console来设置权限,也可以通过Java客户端来设置权限。无论哪种方式,大致的过程如下:

定义resource和scope定义policy根据需要定义角色、组等等定义permission来关联resource(scope)与policy 通过admin console配置

主要就是理解了资源、scope、policy和permission的概念后,在admin console中依次进行配置即可。

通过Java客户端配置

1)引入依赖

org.keycloak keycloak-authz-client ${keycloak.version}

2)编写代码

// 初始化授权客户端对象 AuthzClient authzClient = AuthzClient.create(); // 获取pat对象 ProtectionResource protection = authzClient.protection(); // 创建资源(resource)和scope,这里创建的资源名称为test-res,scope为create-scope, // URI为/admin/*,类型为test:api ResourceRepresentation res = new ResourceRepresentation("test-res", Set.of(new ScopeRepresentation("create-scope")), Set.of("/admin/*"), "test:api"); res.setOwnerManagedAccess(true); ProtectedResource resClient = protection.resource(); ResourceRepresentation existingRes = resClient.findByName(res.getName()); if (existingRes != null) { resClient.delete(existingRes.getId()); } res = resClient.create(res); String resId = res.getId(); // 为上述资源创建权限 // 注意:这里创建的权限,在admin console上不可见 UmaPermissionRepresentation umaPerm = new UmaPermissionRepresentation(); umaPerm.setRoles(Set.of("user_premium")); umaPerm.setName("Only premium user can create resources"); umaPerm.setDescription("Allow access to premium users"); umaPerm.setScopes(Set.of("create-scope")); UmaPermissionRepresentation createdUmaPerm = protection.policy(resId).create(umaPerm);

 

建议 建议通过admin console来管理资源/scope/policy/permission可以使用Java来管理资源,但是不建议使用Java来管理policy和permission 使用keycloak设置的权限保护资源

在keycloak上配置了资源、策略、权限以后,可以在资源服务器上来通过PEP进行权限控制。以下是步骤:

配置keycloak的enforcer

新增一个json文件,放在resources目录下,内容大致如下:

{ "realm": "quickstart", "auth-server-url": "http://localhost:8180", "resource": "authz-servlet", "credentials": { "secret": "secret" }, "http-method-as-scope": false } 增加一个Filter来解析上述配置,并拦截用户请求

在Spring Security的FilterChain中,增加ServletPolicyEnforcerFilter来真正执行权限检查。

@Configuration @EnableWebSecurity public class OAuth2ResourceServerSecurityConfiguration { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt) .addFilterAfter(createPolicyEnforcerFilter(), BearerTokenAuthenticationFilter.class); return http.build(); } private ServletPolicyEnforcerFilter createPolicyEnforcerFilter() { return new ServletPolicyEnforcerFilter(new ConfigurationResolver() { @Override public PolicyEnforcerConfig resolve(HttpRequest request) { try { return JsonSerialization.readValue(getClass().getResourceAsStream("/policy-enforcer.json"), PolicyEnforcerConfig.class); } catch (IOException e) { throw new RuntimeException(e); } } }); } @Bean JwtDecoder jwtDecoder(OAuth2ResourceServerProperties properties) { return NimbusJwtDecoder.withJwkSetUri(properties.getJwt().getJwkSetUri()).build(); } } Bonus:利用AuthorizationContext判断权限

除了使用ServletPolicyEnforcerFilter来进行权限检查以外,我们还可以利用AuthorizationContext来手动判断当前用户是否对某项资源有访问权限。示例代码如下:

@GetMapping("/protected/premium") public String premium(@AuthenticationPrincipal Jwt jwt, HttpServletRequest request) { // 获取当前的AuthorizationContext对象 AuthorizationContext context = (AuthorizationContext) request.getAttribute(AuthorizationContext.class.getName()); // 调用context上的方法进行手动判断    if (context.hasPermission("Premium Resource", "GET")) { // do something intersting... } return String.format("Hello, %s!", jwt.getClaimAsString("preferred_username")); } 这种代码,可以用来构建动态菜单。比如,在用户登录以后,通过这种权限判断,来觉得哪些菜单显示/隐藏。 Bonus:利用AuthzClient来操纵资源

通过AuthorizationContext,我们可以获取到AuthzClient,通过它我们就可以创建资源或者进行个别的权限检查...

// 将AuthorizationContext强转成ClientAuthorizationContext ClientAuthorizationContext clientContext = (ClientAuthorizationContext) context; // 从clientContext中获取AuthzClient实例,然后调用它上面的方法 AuthzClient client = clientContext.getClient(); ResourceRepresentation resource = client.protection().resource().findByName("Premium Resource"); System.out.println(resource); Bonus:从JS调用keycloak的API

在JS中,可以通过keycloak提供的keycloak-authz.js的API来进行权限判断。

首先,需要引入keycloak-authz.js文件

然后调用其上的API在JS端进行权限检查和控制。比如:

// prepare a authorization request with the permission ticket const authorizationRequest = {}; authorizationRequest.ticket = ticket; // send the authorization request, if successful retry the request Identity.authorization.authorize(authorizationRequest).then(function (rpt) { // onGrant }, function () { // onDeny }, function () { // onError });



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3